#include"Task.hpp"
#include<string>
#include<vector>
#include<stdlib.h>
#include<assert.h>
#include<unistd.h>
#include<ctime>
#include<sys/wait.h>
#include<sys/stat.h>
using namespace std;

const int processnum=5;
std::vector<task_t> tasks;

//先描述
class channel   //管理管道的结构体
{
public:
    channel(int cmdfd,int slaverid,const std::string processname)
    :_cmdfd(cmdfd),_slaverid(slaverid),_processname(processname)
    {}
public:
    int _cmdfd; //文件描述符，告诉我们往哪个子进程去写
    pid_t _slaverid;  //子进程PID
    std::string _processname; //子进程名字———方便我们打印日志
};

void slaver()
{
    while(true)
    {
        int cmdcode=0;
        int n=read(0,&cmdcode,sizeof(int));
        if(n==sizeof(int))
        {
            //执行cmdcode对应的任务列表
            cout<<"slaver say@ get a command: "<<getpid()<<" : cmdcode: "<<cmdcode<<endl;
            tasks[cmdcode]();
        }
        if(n==0) break;
    }
}
void Initprocess(std::vector<channel> * channels)
{
    //version 2：确保每一个子进程都只有一个写段
    vector<int> oldfds;
    for(int i=0;i<processnum;i++)
    {
        int pipefd[2];
        int n=pipe(pipefd);
        assert(!n);
        (void)n;

        pid_t id=fork();
        if(id==0)  //child
        {
            for(auto fd : oldfds) close(fd);
            close(pipefd[1]);
            dup2(pipefd[0],0);   //重定向：转变为从键盘中来读
            close(pipefd[0]);
            slaver();
            cout<<"process: "<<getpid()<<" quit"<<endl;
            exit(0);
        }
        //father
        close(pipefd[0]);
        //添加channel字段
        std::string name ="process-"+std::to_string(i);
        channels->push_back(channel(pipefd[1],id,name));
        oldfds.push_back(pipefd[1]);
    }
}
void Debug(const std::vector<channel> & channels)
{
    for(const auto &c:channels)
    {
        std::cout<<c._cmdfd<<" "<<c._slaverid<<" "<<c._processname<<std::endl;
    }
}
void ctrlSlaver(const std::vector<channel> & channels)
{
    for(int i=1;i<=5;i++)
    {
        //1.选择任务
        int cmdcode=rand()%tasks.size();
        //2.选择进程
        int processpos = rand()%channels.size();  //选择方式：随机选择


        std::cout<<"father say: "<<"cmdcode: "<<cmdcode<<" alread sendto: "<<channels[processpos]._cmdfd
        <<" processname: "<<channels[processpos]._processname<<endl;
        //3.发送任务
        write(channels[processpos]._cmdfd,&cmdcode,sizeof(cmdcode));

        sleep(1);
    }
}
void QuitProcess(const std::vector<channel> & channels)
{
    for(int i=0;i<channels.size();i++) close(channels[i]._cmdfd);
    sleep(5);
    for(const auto &c:channels) waitpid(c._slaverid,nullptr,0);
}
int main()
{
    LoadTask(&tasks);
    srand(time(nullptr)^getpid()^1023);  //种一颗随机数的种子
    //再组织
    std::vector<channel> channels;
    //1.初始化
    Initprocess(&channels);
    //test
    Debug(channels);
    //2.开始控制子进程
    ctrlSlaver(channels);
    //3.清理收尾
    QuitProcess(channels);

    // sleep(1000);
    return 0;
}